﻿#include"CentralCache.h"


//CentralCache* CentralCache::_owner=nullptr; 饿汉要加锁
CentralCache CentralCache::_owner;


// 获取⼀个⾮空的Span
span* CentralCache::GetOneSpan(SpanList& list, size_t size)
{
	//当前对应桶的Span链表中有非空对象则直接返回，没有向PageCache要
	struct span* cur = list.Begin();
	while (cur != list.End())
	{
		if (cur->_freeList != nullptr)
			return cur;
		cur = cur->next;
	}


	//对于页管理加锁
	PageCache::GetInstence()->_pageMtx.lock();
	//当前桶没有合适的内存，向PageCache要
	span* newSpan = PageCache::GetInstence()->NewSpan(SizeClass::NumMovePage(size));
	PageCache::GetInstence()->_pageMtx.unlock();


	// 完善Span内容
	newSpan->_freeList = (void*)(newSpan->_pageId << PAGE_SHIFT); // 向堆直接申请空间是按页拿的
	char* start = (char*)newSpan->_freeList;
	char* end = start + (newSpan->_length << PAGE_SHIFT);
	newSpan->_objSize = size;

	// 将内存连接起来，最后一个指向nullptr
	while (start < end)
	{
		Next(start) = start + size;
		start += size;  // 加的应当是对齐后的大小
	}
	Next(end - size) = nullptr;


	// 插入链表管理
	list.PushFront(newSpan);

	return newSpan;
}


// 从中⼼缓存获取⼀定数量的对象给thread Cache
size_t CentralCache::FetchRangeObj(void*& start, void*& end, size_t batchNum, size_t size)
{
	int index = SizeClass::Index(size);

	// 加桶锁，放在多进程竞争
	_spanLists[index]._mutex.lock();

	// 获取一个非空span
	span* span1 = GetOneSpan(_spanLists[index], size);


	//计算实际分割个数
	size_t realNum = 1;
	start = span1->_freeList;
	end = start;

	// 不断向后移动
	for (int i = 0; i < batchNum - 1 && Next(end); i++)
	{
		realNum++;
		end = Next(end);
	}

	// 处理span剩下的内存
	span1->_freeList = Next(end);
	Next(end) = nullptr;
	span1->_useCount += realNum; // 该span使用了多少个对象


	// 解除桶锁
	_spanLists[index]._mutex.unlock();

	return realNum;
}







// 内存回到Span中
void CentralCache::ReleaseListToSpans(void* start, size_t size)
{
	int index = SizeClass::Index(size);

	// 加桶锁
	_spanLists[index]._mutex.lock();

	while (start)
	{
		void* next = Next(start);
		span* curSpan = PageCache::GetInstence()->MapObjectToSpan(start);

		// 头插对应span
		Next(start) = curSpan->_freeList;
		curSpan->_freeList = start;
		curSpan->_useCount--;

		// 如果_useCount为0，就向Page返回
		if (curSpan->_useCount==0)
		{
			
			// 在原来spanList删除该span, 交给PageCache管理
			_spanLists[index].Erase(curSpan);
			curSpan->next = curSpan->prev = nullptr;
			curSpan->_freeList = nullptr;

			PageCache::GetInstence()->_pageMtx.lock();

			PageCache::GetInstence()->ReleaseSpanToPageCache(curSpan);

			PageCache::GetInstence()->_pageMtx.unlock();
		}
		start = next;
	}

	_spanLists[index]._mutex.unlock();
}




